/* 逻辑分析仪SUMP协议示例代码

   此示例代码属于公共领域（或根据您的选择采用CC0许可）

   除非适用法律要求或以书面形式同意，本软件按"原样"分发，
   没有任何明示或暗示的担保或条件。
*/

// 包含必要的头文件
#include "freertos/FreeRTOS.h" // FreeRTOS操作系统头文件
#include "freertos/task.h"     // FreeRTOS任务相关头文件
#include "driver/uart.h"       // ESP32 UART驱动头文件
#include "driver/gpio.h"       // ESP32 GPIO驱动头文件
#include "esp_log.h"           // ESP32日志头文件
#include <string.h>

// 包含自定义头文件
#include "logic_analyzer_pin_definition.h" // 逻辑分析仪引脚定义
#include "logic_analyzer_hal.h"            // 逻辑分析仪硬件抽象层

#include "logic_analyzer_const_definition.h" // 逻辑分析仪常量定义
#include "logic_analyzer_sump_definition.h"  // SUMP协议定义
#include "logic_analyzer_sump.h"             // SUMP协议实现

#include "logic_analyzer_cdc.h" // USB CDC通信相关

// 定义静态变量
static int first_trigger_pin = 0; // 第一个触发引脚编号
static int first_trigger_val = 0; // 第一个触发引脚的值
static int divider = 0;           // 分频器值
static int readCount = 0;         // 读取计数
static int delayCount = 0;        // 延迟计数

// 声明静态函数
static void sump_write_data(uint8_t *buf, int len);                  // 写入数据
static void sump_writeByte(uint8_t byte);                            // 写入单个字节
static void sump_cmd_parser(uint8_t cmdByte);                        // 命令解析器
static void sump_get_metadata();                                     // 获取元数据
static void sump_capture_and_send_samples();                         // 捕获并发送样本
static void sump_la_cb(uint8_t *buf, int cnt, int clk, int channel); // 逻辑分析仪回调函数

// 声明公共函数
void logic_analyzer_init(void);  // 逻辑分析仪初始化
void logic_analyzer_denit(void); // 逻辑分析仪反初始化

// SUMP协议配置结构体，从menuconfig中获取
static logic_analyzer_config_t la_cfg = {
    .pin = { LA_PIN_0, LA_PIN_1, LA_PIN_2, LA_PIN_3, LA_PIN_4, LA_PIN_5, LA_PIN_6, LA_PIN_7,
             LA_PIN_8, LA_PIN_9, LA_PIN_10, LA_PIN_11, LA_PIN_12, LA_PIN_13, LA_PIN_14, LA_PIN_15 }, // 16个引脚
    .pin_trigger = LA_PIN_TRIGGER,                                                                   // 触发引脚
    .trigger_edge = LA_PIN_EDGE,                                                                     // 触发边沿
    .number_of_samples = LA_SAMPLE_COUNT,                                                            // 样本数量
    .sample_rate = LA_SAMPLE_RATE,                                                                   // 采样率
    .number_channels = LA_ANALYZER_CHANNELS,                                                         // 通道数量
    .samples_to_psram = LA_ANALYZER_PSRAM,                                                           // 是否使用PSRAM
    .meashure_timeout = LA_DEFAULT_TiMEOUT,                                                          // 默认超时时间
    .logic_analyzer_cb = sump_la_cb                                                                  // 回调函数
};

// 硬件参数结构体
static logic_analyzer_hw_param_t la_hw;

/**
 * @brief 捕获并发送样本数据
 */
static void sump_capture_and_send_samples()
{
    la_cfg.number_of_samples = readCount;                           // 设置样本数量
    la_cfg.sample_rate = PULSEVIEW_MAX_SAMPLE_RATE / (divider + 1); // 计算采样率

    // 设置触发引脚
    if (first_trigger_pin >= 0) {
        la_cfg.pin_trigger = la_cfg.pin[first_trigger_pin];
    } else {
        la_cfg.pin_trigger = -1; // 无触发
    }

    la_cfg.trigger_edge = first_trigger_val ? GPIO_INTR_POSEDGE : GPIO_INTR_NEGEDGE; // 设置触发边沿
    //miduo add
    ESP_LOGI("mdlink", "pin_trigger:%d, trigger_edge:%d", la_cfg.pin_trigger, la_cfg.trigger_edge);
    // 启动逻辑分析仪
    int err = start_logic_analyzer(&la_cfg);
    if (err) {
        return;
    }
}
#define LOGIC_USB_WRITE_TMP_SIZE (1024*2) // 
/**
 * @brief 逻辑分析仪回调函数，处理采集到的数据
 * @param buf 数据缓冲区
 * @param cnt 数据计数
 * @param clk 时钟
 * @param channels 通道数
 */
static void sump_la_cb(uint8_t *buf, int cnt, int clk, int channels)
{
    if (buf == NULL) {
        printf("缓冲区为空\n");
        return;
    }

    // sigrok协议要求数据逆序发送
    // 对于PSRAM，burst对齐可能导致cnt小于readCount，需要补零
    //int zero_sample = 0;
    int diff = readCount - cnt;     //与要求的采样点数差值
    char logic_analyzer_data[LOGIC_USB_WRITE_TMP_SIZE]; // 逻辑分析仪数据缓冲区
    // uint8_t tmp = 0;
    // uint8_t dug[16] = { 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0 };
    if (channels == 8) { // 8通道处理
        printf("8通道模式\n");
#define LOGIC_WAY_8_2 1
#if LOGIC_WAY_8_1
        /***********************在原缓冲区上处理数据逆序*************************/
        // 直接在原缓冲区上处理数据逆序
        uint8_t *start = buf;
        uint8_t *end = buf + cnt - 1;

        // 反转缓冲区中的数据
        while (start < end) {
            uint8_t temp = *start;
            *start = *end;
            *end = temp;
            start++;
            end--;
        }

        // 发送实际数据部分
        sump_write_data((uint8_t *)buf, cnt);
        int sent_samples = 0;
        memset(logic_analyzer_data, 0, LOGIC_USB_WRITE_TMP_SIZE);
        // 发送补零部分
        while (sent_samples < diff) {
            int chunk = (diff - sent_samples) > LOGIC_USB_WRITE_TMP_SIZE? LOGIC_USB_WRITE_TMP_SIZE : (diff - sent_samples); //MIN(LOGIC_USB_WRITE_TMP_SIZE, diff - sent_samples);
            sump_write_data((uint8_t *)logic_analyzer_data, chunk);
            sent_samples += chunk;
        }


#elif LOGIC_WAY_8_2

        uint8_t *bufff = (uint8_t *)buf + readCount - 1 - diff;
        ESP_LOGI("mdlink", "readCount%d,cnt:%d, diff:%d, clk:%d", readCount, cnt, diff, clk);
        memset(logic_analyzer_data, 0, diff);

        //10K 2M
        for (int i = diff; i < readCount; i++) {
            
            //!diff不能超过 LOGIC_USB_WRITE_TMP_SIZE
            // if (i < diff) { // 补零
            //     //printf("补零样本 8\n");
            //     logic_analyzer_data[i % LOGIC_USB_WRITE_TMP_SIZE] = 0;
            //     //logic_analyzer_data[i % 1024] = dug[i];
            //     //    sump_write_data((uint8_t *)(&zero_sample), 1);
            // } else {
                //tmp = !tmp;
                //logic_analyzer_data[i % 1024] = tmp;
                logic_analyzer_data[i % LOGIC_USB_WRITE_TMP_SIZE] = bufff[0];
                //printf("发送样本\n");
                //sump_write_data((uint8_t *)(bufff), 1);
                bufff--;
            //}
            if ((i + 1) % LOGIC_USB_WRITE_TMP_SIZE == 0) {
                //ESP_LOGI("mdlink", "发送数据 %d", i / LOGIC_USB_WRITE_TMP_SIZE);
                sump_write_data((uint8_t *)(logic_analyzer_data), LOGIC_USB_WRITE_TMP_SIZE);
            }
        }
        /*最后一组数据,可以是不足1024的，也可以是零包*/
        sump_write_data((uint8_t *)logic_analyzer_data, readCount % LOGIC_USB_WRITE_TMP_SIZE);
        //todo 要等待发送完毕,这个函数才能返回,因为logic_analyzer_data是局部变量,会在函数结束时自动释放
        //! 这里只是取巧一下,如果不延时，logic_analyzer_data马上释放，就有脏数据，bug
        vTaskDelay(pdMS_TO_TICKS(100)); // 延迟100ms
#endif                                  //LOGIC_WAY_8_2
    } else if (channels == 16) {        // 16通道处理
        uint16_t *bufff = (uint16_t *)buf + readCount - 1 - diff;
        for (int i = 0; i < readCount; i++) {
            if (i < diff) { // 补零
                printf("补零样本 16\n");
                //sump_write_data((uint8_t *)(&zero_sample), 2);
            } else {
                sump_write_data((uint8_t *)(bufff), 2);
                bufff--;
            }
        }
    } else { // 4通道处理
        uint8_t *bufff = (uint8_t *)buf + (readCount / 2) - 1 - diff;
        for (int i = 0; i < readCount; i++) {
            if (i < diff) { // 补零
                printf("补零样本 4\n");
                //sump_write_data((uint8_t *)(&zero_sample), 1);
            } else {
                if (i & 1) {
                    sump_writeByte(*bufff & 0xf);
                    bufff--;
                } else {
                    sump_writeByte((*bufff >> 4) & 0xf);
                }
            }
        }
    }
}

/**
 * @brief 配置UART（已注释掉，改用CDC）
 */
static void sump_config_uart()
{
    // 这部分代码已被注释，改用USB CDC通信
}

/**
 * @brief 获取4字节命令
 * @param cmd 命令缓冲区
 */
static void sump_getCmd4(uint8_t *cmd)
{
    logic_analyzer_cdc_read(cmd, 4); // 通过CDC读取4字节命令
}

/**
 * @brief 获取单字节命令
 * @return 读取到的命令字节
 */
static uint8_t sump_getCmd()
{
    uint8_t buf = 0;
    logic_analyzer_cdc_read((const uint8_t *)&buf, 1); // 通过CDC读取1字节
    return buf;
}
/* 互斥量句柄 */
SemaphoreHandle_t logic_write_SemBin;
/**
 * @brief 写入数据
 * @param buf 数据缓冲区
 * @param len 数据长度
 */
static void sump_write_data(uint8_t *buf, int len)
{
    //获取二进制信号量
    xSemaphoreTake(logic_write_SemBin, pdMS_TO_TICKS(1000));
    logic_analyzer_cdc_write((const uint8_t *)buf, len); // 通过CDC写入数据
}

/**
 * @brief 写入单字节
 * @param byte 要写入的字节
 */
static void sump_writeByte(uint8_t byte)
{
    logic_analyzer_cdc_write((const uint8_t *)&byte, 1); // 通过CDC写入单字节
}
// 任务句柄
static TaskHandle_t xHandle_logic_analyzer_sump = NULL;
//static bool exit_logic_sump = 0;
/**
 * @brief SUMP协议任务主循环
 * @param arg 任务参数（未使用）
 */
static void logic_analyzer_sump_task(void *arg)
{
    // 获取硬件参数
    la_hw.current_channels = la_cfg.number_channels; //多少通道
    la_hw.current_psram = la_cfg.samples_to_psram;   //是否使用PSRAM
    // 获取硬件参数()
    logic_analyzer_get_hw_param(&la_hw);
    // 二进制信号量
    logic_write_SemBin = xSemaphoreCreateBinary();
    xSemaphoreGive(logic_write_SemBin); //
    sump_config_uart();                 // 配置UART（实际使用CDC）

    while (1) {
        // if (exit_logic_sump)
        // {
        //     xHandle_logic_analyzer_sump = NULL;
        //     ESP_LOGI("debug", "退出SUMP协议任务 1");
        //     vTaskDelete(NULL);
        // }
        uint8_t cmd = sump_getCmd(); // 获取命令
        //ESP_LOGE("miduo", "收到命令：%02x", cmd);
        sump_cmd_parser(cmd);         // 解析命令
        
        vTaskDelay(pdMS_TO_TICKS(15)); // 延迟5ms
    }
}



/**
 * @brief 启动SUMP协议任务
 */
void logic_analyzer_sump(void)
{
    if (xHandle_logic_analyzer_sump != NULL) {
        vTaskDelete(xHandle_logic_analyzer_sump); // 如果任务已存在，先删除
    }
    //exit_logic_sump = 0;
    xTaskCreate(logic_analyzer_sump_task, "logic_sump", 1024 * 4, NULL, 5, &xHandle_logic_analyzer_sump); // 创建任务
}

/**
 * @brief 停止SUMP协议任务
 */
void logic_analyzer_sump_denit(void)
{
    // if (!exit_logic_sump) {
    //     exit_logic_sump = 1; // 设置退出标志
    if (xHandle_logic_analyzer_sump){
        //ESP_LOGI("debug", "退出SUMP协议任务 2");
        vTaskDelete(xHandle_logic_analyzer_sump); // 删除任务
        xHandle_logic_analyzer_sump = NULL;
    }
    //}
    if (logic_write_SemBin != NULL) {
        vSemaphoreDelete(logic_write_SemBin);
        logic_write_SemBin = NULL;
    }
}
char sump_id_buf[] = "1ALS";

/**
 * @brief SUMP协议命令解析器
 * @param cmdByte 命令字节
 */
static void sump_cmd_parser(uint8_t cmdByte)
{
    static int trigger = 0;        // 触发掩码
    static int trigger_values = 0; // 触发值
    union ucmd {
        uint32_t u_cmd32;    // 32位命令
        uint16_t u_cmd16[2]; // 16位命令数组
        uint8_t u_cmd8[4];   // 8位命令数组
    } cmd;

    switch (cmdByte) {
        case SUMP_RESET: // 复位命令
            break;

        case SUMP_QUERY: // ID
            printf("SUMP查询\n");
            sump_write_data((uint8_t *)sump_id_buf, 4); // 返回设备标识
            break;

        case SUMP_ARM: // 开始捕获
            printf("捕获并发送样本\n");
            sump_capture_and_send_samples();
            break;

        case SUMP_TRIGGER_MASK_CH_A: // 设置通道A触发掩码
            printf("设置通道A触发掩码\n");
            sump_getCmd4(cmd.u_cmd8);
            trigger = cmd.u_cmd32 & 0xffff;
            first_trigger_pin = -1; // 默认无触发
            if (trigger) {
                for (int i = 0; i < 16; i++) {
                    if ((trigger >> i) & 0x1) {
                        first_trigger_pin = i; // 找到第一个触发引脚
                        break;
                    }
                }
            }
            break;

        case SUMP_TRIGGER_VALUES_CH_A: // 设置通道A触发值
            printf("设置通道A触发值\n");
            sump_getCmd4(cmd.u_cmd8);
            trigger_values = cmd.u_cmd32 & 0xffff;
            first_trigger_val = 0;
            if (trigger) {
                first_trigger_val = (trigger_values >> first_trigger_pin) & 1; // 获取触发值
            }
            break;

        // 以下命令未实现具体功能，仅读取数据
        case SUMP_TRIGGER_MASK_CH_B:
        case SUMP_TRIGGER_MASK_CH_C:
        case SUMP_TRIGGER_MASK_CH_D:
        case SUMP_TRIGGER_VALUES_CH_B:
        case SUMP_TRIGGER_VALUES_CH_C:
        case SUMP_TRIGGER_VALUES_CH_D:
        case SUMP_TRIGGER_CONFIG_CH_A:
        case SUMP_TRIGGER_CONFIG_CH_B:
        case SUMP_TRIGGER_CONFIG_CH_C:
        case SUMP_TRIGGER_CONFIG_CH_D:
            sump_getCmd4(cmd.u_cmd8);
            break;

        case SUMP_SET_DIVIDER: // 设置分频器
            sump_getCmd4(cmd.u_cmd8);
            divider = cmd.u_cmd32 & 0xffffff;
            break;

        case SUMP_SET_READ_DELAY_COUNT: // 设置读取延迟计数
            sump_getCmd4(cmd.u_cmd8);
            readCount = ((cmd.u_cmd16[0] & 0xffff) + 1) * 4;
            delayCount = ((cmd.u_cmd16[1] & 0xffff) + 1) * 4;
            ESP_LOGI("mdlink", "readCount:%d, delayCount:%d", readCount, delayCount);
            break;

        case SUMP_SET_BIG_READ_CNT: // 设置大读取计数
            sump_getCmd4(cmd.u_cmd8);
            readCount = (cmd.u_cmd32 + 1) * 4;
            ESP_LOGI("mdlink", "readCount:%d", readCount);
            break;
            /*          不处理延迟计数            */
            // case SUMP_SET_DELAY_COUNT:// 设置延迟计数
            //     sump_getCmd4(cmd.u_cmd8);
            //     delayCount =(cmd.u_cmd32 + 1) * 4;
            //     ESP_LOGI("mdlink", "delayCount:%d", delayCount);

            break;
        case SUMP_SET_FLAGS: // 设置标志
            sump_getCmd4(cmd.u_cmd8);
            break;

        case SUMP_GET_METADATA: // 获取元数据
            sump_get_metadata();
            break;

        case SUMP_SELF_TEST: // 自检（未实现）
            break;

        default: // 未知命令
            break;
    }
}

/**
 * @brief 获取并发送设备元数据
 */
static void sump_get_metadata()
{
    // 获取硬件参数
    la_hw.current_channels = la_cfg.number_channels;
    la_hw.current_psram = la_cfg.samples_to_psram;
    logic_analyzer_get_hw_param(&la_hw);
    // 构建元数据缓冲区
    uint8_t buffer[128] = { 0 };
    uint32_t offset = 0;
    /* 设备名称 */
    buffer[offset++] = 0x01;
    memcpy(&buffer[offset], "MdLink Logic Analyzer", 22);
    offset += 22;

    /* 固件版本 */
    buffer[offset++] = 0x02;
    memcpy(&buffer[offset], "01092025", 9);
    offset += 9;

    /* 采样内存大小 */
    uint32_t capture_size = (la_hw.current_channels > 4) ?
                                (la_hw.max_sample_cnt * (la_hw.current_channels / 8)) :
                                la_hw.max_sample_cnt;
    buffer[offset++] = 0x21;
    buffer[offset++] = (capture_size >> 24) & 0xFF;
    buffer[offset++] = (capture_size >> 16) & 0xFF;
    buffer[offset++] = (capture_size >> 8) & 0xFF;
    buffer[offset++] = (capture_size >> 0) & 0xFF;

    /* 采样率 */
    uint32_t capture_speed = la_hw.max_sample_rate;
    buffer[offset++] = 0x23;
    buffer[offset++] = (capture_speed >> 24) & 0xFF;
    buffer[offset++] = (capture_speed >> 16) & 0xFF;
    buffer[offset++] = (capture_speed >> 8) & 0xFF;
    buffer[offset++] = (capture_speed >> 0) & 0xFF;

    /* 探头数量 */
    buffer[offset++] = 0x40;
    buffer[offset++] = (la_hw.current_channels > 4) ?
                           (la_hw.current_channels & 0xFF) :
                           8;

    /* 协议版本 */
    buffer[offset++] = 0x41;
    buffer[offset++] = 0x02;

    /* 结束标志 */
    buffer[offset++] = 0x00;
    ESP_LOGI("MdLink", "探头数量：%" PRIu32 " 采样内存大小：%" PRIu32 " 采样率：%" PRIu32,
             la_hw.current_channels, capture_size, capture_speed);
    /* 一次性发送所有元数据 */
    logic_analyzer_cdc_write(buffer, offset);
}

/**
 * @brief 逻辑分析仪初始化
 */
void  logic_analyzer_init(void)
{
    logic_analyzer_cdc_start(); // 启动CDC通信
    logic_analyzer_sump();      // 启动SUMP协议任务
}

/**
 * @brief 逻辑分析仪反初始化
 */
void logic_analyzer_denit(void)
{
    logic_analyzer_cdc_stop();   // 停止CDC通信
    logic_analyzer_sump_denit(); // 停止SUMP协议任务
}